/*
 * Description: 通信客户端代理基类，实现了客户端的基础通信功能。
 */
#ifndef GUEST_LINK_I_SERVICE
#define GUEST_LINK_I_SERVICE

#include <string>
#include <thread>
#include <mutex>
#include "guest2host.pb.h"
#include "guest_socket.h"
#include "call_records_cache.h"
#include "connect_common.h"
#include "error.h"

namespace COMMON {
class IService {
public:
    virtual bool IsConnected() const final;

protected:
    /*******************************************************************************
    函 数 名        :  IService
    功能描述        :  构造函数。
    输入参数        :  server: 所代理的服务端名称
                      client: 发起连接的客户端名称
    输出参数        :  无
    返 回 值        :  成功返回0，失败-1
    *******************************************************************************/
    IService(const std::string &server, const std::string &client);

    virtual ~IService();

    /*******************************************************************************
    函 数 名        :  EstablishEventChannel
    功能描述        :  创建事件通道，需要传入socket路径。创建返回成功之后，可以使用CallMethod方法簇向远端发送指令。
    输入参数        :  socketInfo: sock路径
    输出参数        :  无
    返 回 值        :  成功返回0，失败-1
    *******************************************************************************/
    int EstablishEventChannel(int port,
        const std::string& userId = "", const std::string& appId = "", const std::string& vmName = "");

    /*******************************************************************************
    函 数 名		:  CallMethodSync
    功能描述		:  同步事件发送，需要传入函数ID，参数和放置返回值的指针。
                       函数会在接收到远端返回值之后，并且填充好之后返回。
                       如果没有参数请使用GuestLink.proto中的Void类型。
    输入参数		:  id:函数ID
                       parameters:函数参数
                       returnValue:返回值指针
                       asyncInService:服务端是否同步阻塞，默认阻塞（非同步阻塞时，服务端会开线程处理该同步事件）
    输出参数		:  None
    返 回 值		:  成功返回0, 失败-1
    *******************************************************************************/
    int CallMethodSync(int id, const google::protobuf::MessageLite &parameters,
                        google::protobuf::MessageLite *result, bool asyncInService = false);

    /*******************************************************************************
    函 数 名		:  CallMethodAsync
    功能描述		:  异步事件发送，需要传入函数ID和参数。
                       函数会在发送成功或者失败之后立刻返回。
                       如果没有参数请使用GuestLink.proto中的Void类型。
    输入参数		:  id:函数ID
                       parameters:函数参数
                       asyncInService:是否异步
    输出参数		:  None
    返 回 值		:  成功返回0, 失败-1
    *******************************************************************************/
    int CallMethodAsync(int id, const google::protobuf::MessageLite &parameters, bool asyncInService = false);

    /*******************************************************************************
    函 数 名		:  OnDisconnected
    功能描述		:  断链事件分发，仅用于事件链接（不支持流链接）
    输入参数		:  None
    输出参数		:  None
    返 回 值		:  None
    *******************************************************************************/
    virtual void OnDisconnected();

    /*******************************************************************************
      函 数 名		:  SetReadTimeout
      功能描述		:  设置读数据超时时间，在创建通道前调用（如：EstablishReadStreamChannel）
      输入参数		:  timeout:超时时间，默认-1:阻塞，单位:s
      输出参数		:  None
      返 回 值		:  None
    *******************************************************************************/
    void SetReadTimeout(int timeout);

    /*******************************************************************************
      函 数 名		:  CloseEventChannel
      功能描述		:  断开事件通道
      输入参数		:  None
      输出参数		:  None
      返 回 值	    :  成功返回0,失败返回-1
    *******************************************************************************/
    int CloseEventChannel();

private:
    /**
     * 重连服务器，子类根据需要override该方法各自实现重连逻辑
     * 返回0表示成功；基类实现默认返回-1，表示失败
     */
    virtual int ReconnectServer();
    /**
     * 断链时尝试重连，内部调用虚函数ReconnectServer
     */
    int InternalReconnectServer();
    /**
     * 断链事件分发，仅用于事件链接（不支持流链接）
     */
    void InternalOnDisconnected();

    /**
     * 断链或析构时销毁所有连接
     */
    void Destroy();

    static void HandleResponse(const std::shared_ptr<MsgSock> &msgSock, void *arg);
    uint32_t GetNextID() const;
    Guest::protobuf::link::Call PackCall(uint32_t callID, int methodID,
        const google::protobuf::MessageLite &parameters, bool asyncInService = false) const;
    int SendMessage(const std::shared_ptr<MsgSock> &msgSock, MessageType type,
        const google::protobuf::MessageLite &message) const;
    int CreateChannel(SocketInfo info, std::shared_ptr<MsgSock> &msgSock);

private:
    std::string m_server = "";
    std::string m_client = "";
    std::shared_ptr<MsgSock> m_msgSock = nullptr;
    CallRecordsCache m_callRecordsCache = {};
    std::atomic<bool> m_connected {false};
    std::mutex m_mutex {};
    int m_curTimeout = DEFAULT_TIME_OUT;
};
}
#endif // GUEST_LINK_I_SERVICE
